"""计划管理工具"""
import json
from typing import List, Dict, Optional
from .sse_helper import send_sse_event

_plan_memory: List[Dict] = []


def load_plan() -> List[Dict]:
    return _plan_memory


def save_plan(plan: List[Dict]):
    global _plan_memory
    _plan_memory = plan


from langchain_core.tools import tool


@tool
def update_plan(plan: List[Dict], merge: bool = False) -> str:
    """
    创建或更新任务计划
    
    Args:
        plan: 任务列表，每个任务包含step和status字段
        merge: 是否合并到现有计划。True=合并更新，False=替换全部
    
    Returns:
        操作结果
    """
    try:
        if not plan:
            return json.dumps({"success": False, "error": "任务列表不能为空"}, ensure_ascii=False)

        if not merge and len(plan) < 2:
            return json.dumps({"success": False, "error": "创建新计划至少需要2个任务"}, ensure_ascii=False)
        
        if merge:
            current_plan = load_plan()
            plan_dict = {item['id']: item for item in current_plan}
            id_order = [item['id'] for item in current_plan]
            
            # 建立内容到ID的映射，用于通过内容匹配
            # 安全获取content，防止KeyError
            content_map = {item.get('content', ''): item['id'] for item in current_plan}
            existing_ids = id_order.copy()
            
            # 判断是否像是完整列表的重述（数量接近）
            is_full_list_update = len(plan) >= len(current_plan)
            
            for i, task in enumerate(plan):
                # 1. 优先使用传入的ID
                task_id = task.get('id')
                
                # 2. 如果没有ID，尝试通过内容匹配
                if not task_id:
                    content = task.get('step', task.get('content', ''))
                    if content:
                        # 2.1 精确匹配
                        if content in content_map:
                            task_id = content_map[content]
                        else:
                            # 2.2 模糊匹配 (简单的包含关系)
                            for existing_content, existing_id in content_map.items():
                                if content in existing_content or existing_content in content:
                                    task_id = existing_id
                                    break
                
                # 3. 如果还是没有ID，使用索引匹配作为兜底
                # 移除 is_full_list_update 限制，因为Agent可能只传了部分任务，但通常是按顺序的
                # 风险：如果Agent只传了第5个任务但没ID，会被匹配成第1个。
                # 改进：只有当 plan 长度与 current_plan 一致时，或者明确是单任务更新且无法匹配时？
                # 这里的逻辑很难完美，但为了防止死循环（即防止错误地新增任务），我们倾向于匹配到现有任务
                if not task_id and i < len(existing_ids):
                    # 只有在不仅没ID，而且连模糊匹配都没匹配上的情况下
                    # 如果 plan 长度明显小于 current_plan，使用索引匹配非常危险
                    # 所以这里我们保留 is_full_list_update 的逻辑，但放宽一点
                    if is_full_list_update:
                         task_id = existing_ids[i]
                
                # 4. 如果还是没有ID，那只能是新增任务了
                if not task_id:
                    task_id = str(len(plan_dict) + 1)
                
                if task_id in plan_dict:
                    # 更新现有任务
                    if 'status' in task:
                        plan_dict[task_id]['status'] = task['status']
                else:
                    # 新增任务
                    plan_dict[task_id] = {
                        'id': task_id,
                        'content': task.get('step', task.get('content', '')),
                        'status': task.get('status', 'pending')
                    }
                    id_order.append(task_id)
            
            new_plan = [plan_dict[task_id] for task_id in id_order if task_id in plan_dict]
        else:
            new_plan = []
            for i, task in enumerate(plan):
                new_plan.append({
                    'id': task.get('id', str(i + 1)),
                    'content': task.get('step', task.get('content', '')),
                    'status': task.get('status', 'pending')
                })
        
        save_plan(new_plan)
        send_sse_event("plan", {"plan": new_plan}, tag="plan_manager")
        return json.dumps({"success": True, "plan": new_plan}, ensure_ascii=False)
        
    except Exception as e:
        print(f"Error in update_plan: {str(e)}")
        return json.dumps({"success": False, "error": f"更新计划时发生错误: {str(e)}"}, ensure_ascii=False)


@tool
def get_plan() -> str:
    """获取当前计划"""
    plan = load_plan()
    send_sse_event("plan", {"plan": plan}, tag="plan_manager")
    return json.dumps({"success": True, "plan": plan}, ensure_ascii=False)


@tool
def clear_plan() -> str:
    """清空计划"""
    save_plan([])
    send_sse_event("plan", {"plan": []}, tag="plan_manager")
    return json.dumps({"success": True}, ensure_ascii=False)


PlanManagerTool = [update_plan, get_plan, clear_plan]
